package telemetry

import (
	"net/http"
	"strconv"
	"time"

	"iot-cloud-platform/internal/auth"

	"github.com/gin-gonic/gin"
	"github.com/google/uuid"
)

// TelemetryController handles telemetry data endpoints
type TelemetryController struct {
	telemetryService *TelemetryService
}

// NewTelemetryController creates a new telemetry controller
func NewTelemetryController(telemetryService *TelemetryService) *TelemetryController {
	return &TelemetryController{
		telemetryService: telemetryService,
	}
}

// SubmitTelemetryData handles telemetry data submission
func (tc *TelemetryController) SubmitTelemetryData(c *gin.Context) {
	var req SubmitTelemetryRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	if err := tc.telemetryService.SubmitTelemetryData(c.Request.Context(), req); err != nil {
		if err == ErrInvalidDeviceID {
			c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid device ID"})
		} else {
			c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to submit telemetry data"})
		}
		return
	}

	c.JSON(http.StatusCreated, gin.H{"message": "Telemetry data submitted successfully"})
}

// SubmitBatchTelemetryData handles batch telemetry data submission
func (tc *TelemetryController) SubmitBatchTelemetryData(c *gin.Context) {
	var req struct {
		Data []SubmitTelemetryRequest `json:"data" binding:"required"`
	}

	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	if len(req.Data) == 0 {
		c.JSON(http.StatusBadRequest, gin.H{"error": "No data provided"})
		return
	}

	if len(req.Data) > 1000 {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Batch size too large (max 1000)"})
		return
	}

	if err := tc.telemetryService.SubmitBatchTelemetryData(c.Request.Context(), req.Data); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to submit batch telemetry data"})
		return
	}

	c.JSON(http.StatusCreated, gin.H{
		"message": "Batch telemetry data submitted successfully",
		"count":   len(req.Data),
	})
}

// GetTelemetryData handles telemetry data retrieval
func (tc *TelemetryController) GetTelemetryData(c *gin.Context) {
	deviceIDStr := c.Param("deviceId")
	deviceID, err := uuid.Parse(deviceIDStr)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid device ID"})
		return
	}

	var req TelemetryQueryRequest
	req.DeviceID = deviceID

	// Parse query parameters
	if startTimeStr := c.Query("start_time"); startTimeStr != "" {
		if startTime, err := time.Parse(time.RFC3339, startTimeStr); err == nil {
			req.StartTime = startTime
		} else {
			c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid start_time format (use RFC3339)"})
			return
		}
	} else {
		req.StartTime = time.Now().Add(-24 * time.Hour) // Default to last 24 hours
	}

	if endTimeStr := c.Query("end_time"); endTimeStr != "" {
		if endTime, err := time.Parse(time.RFC3339, endTimeStr); err == nil {
			req.EndTime = endTime
		} else {
			c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid end_time format (use RFC3339)"})
			return
		}
	} else {
		req.EndTime = time.Now()
	}

	if limitStr := c.Query("limit"); limitStr != "" {
		if limit, err := strconv.Atoi(limitStr); err == nil {
			req.Limit = limit
		}
	}

	if fieldsStr := c.Query("fields"); fieldsStr != "" {
		// Split comma-separated fields
		// req.Fields = strings.Split(fieldsStr, ",")
	}

	req.OrderBy = c.DefaultQuery("order_by", "desc")

	response, err := tc.telemetryService.GetTelemetryData(c.Request.Context(), req)
	if err != nil {
		if err == ErrInvalidDeviceID {
			c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid device ID"})
		} else if err == ErrInvalidTimeRange {
			c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid time range"})
		} else {
			c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to retrieve telemetry data"})
		}
		return
	}

	c.JSON(http.StatusOK, response)
}

// GetAggregatedData handles aggregated telemetry data retrieval
func (tc *TelemetryController) GetAggregatedData(c *gin.Context) {
	deviceIDStr := c.Param("deviceId")
	deviceID, err := uuid.Parse(deviceIDStr)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid device ID"})
		return
	}

	var req AggregatedQueryRequest
	req.DeviceID = deviceID

	// Parse query parameters
	if startTimeStr := c.Query("start_time"); startTimeStr != "" {
		if startTime, err := time.Parse(time.RFC3339, startTimeStr); err == nil {
			req.StartTime = startTime
		} else {
			c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid start_time format (use RFC3339)"})
			return
		}
	} else {
		req.StartTime = time.Now().Add(-24 * time.Hour)
	}

	if endTimeStr := c.Query("end_time"); endTimeStr != "" {
		if endTime, err := time.Parse(time.RFC3339, endTimeStr); err == nil {
			req.EndTime = endTime
		} else {
			c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid end_time format (use RFC3339)"})
			return
		}
	} else {
		req.EndTime = time.Now()
	}

	req.Field = c.Query("field")
	if req.Field == "" {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Field parameter is required"})
		return
	}

	req.Aggregation = c.DefaultQuery("aggregation", "mean")
	req.Window = c.DefaultQuery("window", "1h")

	response, err := tc.telemetryService.GetAggregatedData(c.Request.Context(), req)
	if err != nil {
		if err == ErrInvalidDeviceID {
			c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid device ID"})
		} else if err == ErrInvalidTimeRange {
			c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid time range"})
		} else if err == ErrInvalidAggregation {
			c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid aggregation type"})
		} else {
			c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to retrieve aggregated data"})
		}
		return
	}

	c.JSON(http.StatusOK, response)
}

// GetLatestTelemetryData handles latest telemetry data retrieval
func (tc *TelemetryController) GetLatestTelemetryData(c *gin.Context) {
	deviceIDStr := c.Param("deviceId")
	deviceID, err := uuid.Parse(deviceIDStr)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid device ID"})
		return
	}

	var fields []string
	if fieldsStr := c.Query("fields"); fieldsStr != "" {
		// fields = strings.Split(fieldsStr, ",")
	}

	data, err := tc.telemetryService.GetLatestTelemetryData(c.Request.Context(), deviceID, fields)
	if err != nil {
		if err == ErrInvalidDeviceID {
			c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid device ID"})
		} else if err == ErrNoDataFound {
			c.JSON(http.StatusNotFound, gin.H{"error": "No telemetry data found"})
		} else {
			c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to retrieve latest telemetry data"})
		}
		return
	}

	c.JSON(http.StatusOK, data)
}

// GetDeviceDataSummary handles device data summary retrieval
func (tc *TelemetryController) GetDeviceDataSummary(c *gin.Context) {
	deviceIDStr := c.Param("deviceId")
	deviceID, err := uuid.Parse(deviceIDStr)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid device ID"})
		return
	}

	days := 7 // Default
	if daysStr := c.Query("days"); daysStr != "" {
		if parsedDays, err := strconv.Atoi(daysStr); err == nil && parsedDays > 0 {
			days = parsedDays
		}
	}

	summary, err := tc.telemetryService.GetDeviceDataSummary(c.Request.Context(), deviceID, days)
	if err != nil {
		if err == ErrInvalidDeviceID {
			c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid device ID"})
		} else {
			c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to retrieve device data summary"})
		}
		return
	}

	c.JSON(http.StatusOK, summary)
}

// DeleteTelemetryData handles telemetry data deletion
func (tc *TelemetryController) DeleteTelemetryData(c *gin.Context) {
	// Check if user has admin role
	if !auth.HasRole(c, "admin") {
		c.JSON(http.StatusForbidden, gin.H{"error": "Admin role required"})
		return
	}

	deviceIDStr := c.Param("deviceId")
	deviceID, err := uuid.Parse(deviceIDStr)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid device ID"})
		return
	}

	var req struct {
		StartTime time.Time `json:"start_time" binding:"required"`
		EndTime   time.Time `json:"end_time" binding:"required"`
	}

	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	if err := tc.telemetryService.DeleteTelemetryData(c.Request.Context(), deviceID, req.StartTime, req.EndTime); err != nil {
		if err == ErrInvalidDeviceID {
			c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid device ID"})
		} else if err == ErrInvalidTimeRange {
			c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid time range"})
		} else {
			c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to delete telemetry data"})
		}
		return
	}

	c.JSON(http.StatusOK, gin.H{"message": "Telemetry data deleted successfully"})
}

// GetTelemetryStatistics handles telemetry statistics retrieval
func (tc *TelemetryController) GetTelemetryStatistics(c *gin.Context) {
	// This would typically return user-specific telemetry statistics
	userID, exists := auth.GetCurrentUser(c)
	if !exists {
		c.JSON(http.StatusUnauthorized, gin.H{"error": "User not authenticated"})
		return
	}

	// Mock statistics - in a real implementation, you'd query the database for user-specific data
	stats := map[string]interface{}{
		"user_id":           userID,
		"total_data_points": 0,
		"data_points_today": 0,
		"active_devices":    0,
		"avg_data_rate":     0.0,
		"storage_usage_mb":  0.0,
	}

	c.JSON(http.StatusOK, stats)
}
